package edu.utah.seq.data;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import util.bio.annotation.*;
import util.gen.*;
import edu.utah.seq.data.*;
import trans.tpmap.*;

/**Merges, strips scores, sums identical positions.... of PointData
 * @author Nix
 * */
public class PointDataManipulator {

	//fields
	private File[] pointDataDirectories;
	private HashMap<String, ArrayList<PointData>>[] splitPointData;
	private File saveDirectory;
	private boolean stripScores = false;
	private boolean mergeStrands = false;
	private boolean sumIdenticalPositions = false;
	private int shiftPointData = 0;
	private String chromosome;


	/**For stand alone app.*/
	public PointDataManipulator(String[] args){
		//start clock
		long startTime = System.currentTimeMillis();
		//process args
		processArgs(args);
		//fetch names
		splitPointData = PointData.fetchStrandedPointDataNoMerge (pointDataDirectories);

		//fetch all chromosomes
		HashSet<String> chromosomes = new HashSet<String>();
		chromosomes.addAll(splitPointData[0].keySet());
		chromosomes.addAll(splitPointData[1].keySet());

		//for each chromosome
		Iterator<String> it = chromosomes.iterator();

		while (it.hasNext()){
			chromosome = it.next();
			System.out.println("\t"+chromosome);
			if (stripScores) {
				stripScores(splitPointData[0].get(chromosome));
				stripScores(splitPointData[1].get(chromosome));
			}
			if (shiftPointData !=0){
				shiftPointData(splitPointData[0].get(chromosome));
				shiftPointData(splitPointData[1].get(chromosome));
			}
			if (mergeStrands){
				ArrayList<PointData> all = splitPointData[0].get(chromosome);
				all.addAll(splitPointData[1].get(chromosome));
				PointData merged;
				if (sumIdenticalPositions) merged = PointData.mergePointData(all, true);
				else merged = PointData.combinePointData(all, true);
				merged.writePointData(saveDirectory);
			}
			else {
				if (splitPointData[0].containsKey(chromosome)){
					PointData plus;
					if (sumIdenticalPositions) plus = PointData.mergePointData(splitPointData[0].get(chromosome), true);
					else plus = PointData.combinePointData(splitPointData[0].get(chromosome), true);
					plus.writePointData(saveDirectory);
				}
				if (splitPointData[1].containsKey(chromosome)){
					PointData minus;
					if (sumIdenticalPositions) minus = PointData.mergePointData(splitPointData[1].get(chromosome), true);
					else minus = PointData.combinePointData(splitPointData[1].get(chromosome), true);
					minus.writePointData(saveDirectory);
				}
			}
		}

		//finish and calc run time
		double diffTime = ((double)(System.currentTimeMillis() -startTime))/1000;
		System.out.println("\nDone! "+Math.round(diffTime)+" seconds\n");
	}

	/**Sets all scores to 1. Typically these are a score associated with the alignment (a probability).*/
	public void stripScores (ArrayList<PointData> pdAL){
		if (pdAL == null || pdAL.size() == 0) return;
		int num = pdAL.size();
		for (int i=0; i< num; i++){
			pdAL.get(i).stripScores();
		}
	}

	/**Sets all scores to 1. Typically these are a score associated with the alignment (a probability).*/
	public void shiftPointData (ArrayList<PointData> pdAL){
		if (pdAL == null || pdAL.size() == 0) return;
		int num = pdAL.size();
		for (int i=0; i< num; i++){
			pdAL.get(i).shiftPositions(shiftPointData);
		}
	}

	public static void main(String[] args) {
		if (args.length ==0){
			printDocs();
			System.exit(0);
		}
		new PointDataManipulator(args);
	}		


	/**This method will process each argument and assign new variables*/
	public void processArgs(String[] args){
		Pattern pat = Pattern.compile("-[a-z]");
		System.out.println("\nArguments: "+Misc.stringArrayToString(args, " ")+"\n");
		for (int i = 0; i<args.length; i++){
			String lcArg = args[i].toLowerCase();
			Matcher mat = pat.matcher(lcArg);
			if (mat.matches()){
				char test = args[i].charAt(1);
				try{
					switch (test){
					case 'p': pointDataDirectories = IO.extractFiles(args[++i]); break;
					case 's': saveDirectory = new File(args[++i]); break;
					case 'm': mergeStrands = true; break;
					case 'i': sumIdenticalPositions = true; break;
					case 'd': shiftPointData = Integer.parseInt(args[++i]); break;
					case 'o': stripScores = true; break;
					case 'h': printDocs(); System.exit(0);
					default: Misc.printExit("\nProblem, unknown option! " + mat.group());
					}
				}
				catch (Exception e){
					Misc.printExit("\nSorry, something doesn't look right with this parameter: -"+test+"\n");
				}
			}
		}

		//look for point directories
		if (pointDataDirectories == null || pointDataDirectories[0].isDirectory() == false) Misc.printExit("\nError: cannot find your PointData directories(s)!\n");
		//only one directory look deeper
		if (pointDataDirectories.length == 1){
			File[] otherDirs = IO.extractOnlyDirectories(pointDataDirectories[0]);
			if (otherDirs != null && otherDirs.length > 0) pointDataDirectories = otherDirs;
		}

		//create the save directory
		if (saveDirectory == null) Misc.printExit("\nError: enter a directory name to save results.\n");
		if (saveDirectory.exists() == false) saveDirectory.mkdir();
		else System.out.println("\nWARNING: the save directory exists, will over write files contained within.\n");

	}	

	public static void printDocs(){
		System.out.println("\n" +
				"**************************************************************************************\n" +
				"**                            Point Data Manipulator: Jan 2009                      **\n" +
				"**************************************************************************************\n" +
				"Manipulates point data to merge strands, shift base positions, replace scores with 1\n" +
				"and sum identical positions. If multiple PointData directories are give the data is\n" +
				"merged.\n\n" +

				"Options:\n"+
				"-p Point Data directories, full path, comma delimited. Should contain chromosome\n" +
				"       specific xxx.bar.zip or xxx_-_.bar files.\n"+
				"-s Save directory, full path.\n"+
				"-o Replace PointData scores with 1\n"+
				"-d Shift base position XXX bases 3', defaults to 0\n"+
				"-i Sum identical base position scores\n"+
				"-m Merge strands\n"+

				"\n"+

				"Example: java -Xmx1500M -jar pathTo/USeq/Apps/PointDataManipulator -p\n" +
				"      /Data/Ets1Rep1/,/Data/Ets1Rep2/ -s /Data/MergedEts1 -o -i -m -d 75\n\n"+

		"**************************************************************************************\n");

	}		

}
